//
// Created by xu on 2024/11/22.
//
#include <stdio.h>
#include <stdlib.h>
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#include <libavcodec/avcodec.h>

// 只能推flv格式的数据？
int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <input_file> <rtmp_url>\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *input_file = argv[1];
    const char *rtmp_url = argv[2];

    avformat_network_init();

    AVFormatContext *input_ctx = NULL;
    if (avformat_open_input(&input_ctx, input_file, NULL, NULL) != 0) {
        fprintf(stderr, "Error opening input file\n");
        return EXIT_FAILURE;
    }

    if (avformat_find_stream_info(input_ctx, NULL) < 0) {
        fprintf(stderr, "Error finding stream information\n");
        return EXIT_FAILURE;
    }

    const AVOutputFormat *output_fmt = av_guess_format("flv", NULL, NULL);
    if (!output_fmt) {
        fprintf(stderr, "Error guessing output format\n");
        return EXIT_FAILURE;
    }

    AVFormatContext *output_ctx = NULL;
    if (avformat_alloc_output_context2(&output_ctx, output_fmt, NULL, rtmp_url) < 0) {
        fprintf(stderr, "Error allocating output context\n");
        return EXIT_FAILURE;
    }

    for (int i = 0; i < input_ctx->nb_streams; i++) {
        AVStream *in_stream = input_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(output_ctx, input_ctx->video_codec);
        if (!out_stream) {
            fprintf(stderr, "Error creating output stream\n");
            return EXIT_FAILURE;
        }

        if (avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar) < 0) {
            fprintf(stderr, "Error copying codec context\n");
            return EXIT_FAILURE;
        }
    }

    if (avio_open(&output_ctx->pb, rtmp_url, AVIO_FLAG_WRITE) < 0) {
        fprintf(stderr, "Error opening output URL\n");
        return EXIT_FAILURE;
    }

    if (avformat_write_header(output_ctx, NULL) < 0) {
        fprintf(stderr, "Error writing header\n");
        return EXIT_FAILURE;
    }

    AVPacket packet;
    int frame_index = 0;
    while (1) {
        AVStream *in_stream, *out_stream;
        if (av_read_frame(input_ctx, &packet) < 0)
            break;

        in_stream = input_ctx->streams[packet.stream_index];
        out_stream = output_ctx->streams[packet.stream_index];

        packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
        packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF);
        packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
        packet.pos = -1;

        if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
            fprintf(stderr, "Error writing frame\n");
            return EXIT_FAILURE;
        }

        printf("Write %8d frames to output URL\n", frame_index);
        av_packet_unref(&packet);
        frame_index++;
    }

    av_write_trailer(output_ctx);

    avio_close(output_ctx->pb);
    avformat_free_context(output_ctx);

    avformat_close_input(&input_ctx);

    return EXIT_SUCCESS;
}